using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Xml;
using System.Net;
using TALoaders;
using TAAlert.CommonUtils;

namespace TAAlert.Alerts
{
    class VEMAAlert : Alert
    {
        private static readonly string N1_LOW_VOL_XML = "n1HigVol";
        private static readonly string N2_HIGH_VOL_XML = "n2LowVol";
        private static readonly string VOL_TREASHOLD = "volTreashold";
        private int n1LowVolM;    // EMA period for vol below volT
        private int n2HighVolM;    // EMA period for vol above volT
        private double volTM;   // Treashold volatility
        private double price0M;     // Yesterday's price
        private DateTime lastHistDateM; // Yesterday's date
        private double ema1LowVol0M = 0;    // yesterday's low-vol EMA
        private double ema2HighVol0M = 0;   // yesterday's high-vol EMA
        private double vol0M;       // yesterday's volatility

        static private readonly TraceSwitch traceM = new TraceSwitch("VEMAAlert", "Debug info for VEMA Alert class");

        public VEMAAlert(BaseLoader loader, string ticker, int n1LowVol, int n2HighVol, double volTreashold)
            : base(loader, ticker, StrategyName.VEMA)
        {
            Debug.WriteLineIf(traceM.TraceInfo, "--> VEMAAlert(" + loader.Loader.ToString() +
                ", " + ticker + ", n1=" + n1LowVol + ", n2=" + n2HighVol + ", volTreashold=" + volTreashold + ")");
            this.n1LowVolM = n1LowVol;
            this.n2HighVolM = n2HighVol;
            this.volTM = volTreashold;
            this.commonConstructor();
        }

        public VEMAAlert(XmlReader r)
            : base(r, StrategyName.VEMA)
        {
            this.n1LowVolM = r.ReadElementContentAsInt(N1_LOW_VOL_XML, "");
            this.n2HighVolM = r.ReadElementContentAsInt(N2_HIGH_VOL_XML, "");
            this.volTM = r.ReadElementContentAsDouble(VOL_TREASHOLD, "");
            r.ReadEndElement();

            this.commonConstructor();
        }

        /// <summary>Common part of all constructors</summary>
        private void commonConstructor()
        {
            DateTime end = DateTime.Now.Date.AddDays(-1);
            DateTime start = end.AddYears(-1);
            SortedList<DateTime, double> hPrice;
            try
            {
                hPrice = loaderM.getHistoricalPrices(this.Ticker, start, end, QuoteType.AdjClose);
            }
            catch (WebException wex)
            {
                throw new WebException("VEMAAlert: Cannot load ticker: '" + base.Ticker + "' using loader:" + base.loaderM.Loader + "\n" + wex.Message);
            }

            this.price0M = hPrice.Values[hPrice.Count - 1];
            this.lastHistDateM = hPrice.Keys[hPrice.Count - 1];
            if (this.n1LowVolM > 0) // for n=0 the strategy is neutral
            {
                List<double> hEma = EMAEvaluator.calcEMAArray(hPrice.Values, this.n1LowVolM);
                this.ema1LowVol0M = hEma[hEma.Count - 1];
            }
            if (this.n2HighVolM > 0) // for n=0 the strategy is neutral
            {
                List<double> hEma = EMAEvaluator.calcEMAArray(hPrice.Values, this.n2HighVolM);
                this.ema2HighVol0M = hEma[hEma.Count - 1];
            }
            List<double> hVol = EMAEvaluator.calcEMAVolatilityArray(hPrice.Values);
            this.vol0M = hVol[hVol.Count - 1];
        }

        // Latest signal value
        public override Signal evalAlert(out string[] info)
        {
            string timeStamp;
            double price1 = loaderM.getLastPrice(this.Ticker, out timeStamp);
            double ema1 = EMAEvaluator.calcEMA(this.ema1LowVol0M, this.n1LowVolM, price1);
            double ema2 = EMAEvaluator.calcEMA(this.ema2HighVol0M, this.n2HighVolM, price1);
            double vol1 = EMAEvaluator.calcEMAVolatility(this.vol0M, this.price0M, price1); 
            info = new string[9];
            info[0] = string.Format("Price = {0:.####}       (as of {1})", price1, timeStamp);
            info[1] = string.Format("ema1LowVol({0}) = {1:.####}", this.n1LowVolM, ema1);
            info[2] = string.Format("ema2HighVol({0}) = {1:.####}", this.n2HighVolM, ema2);
            info[3] = string.Format("volatility = {0:P1}", vol1);
            info[4] = "Old Signal = " + this.oldAlert();
            info[5] = string.Format("Old Price = {0:.####}   (as of {1})", price0M, lastHistDateM.ToShortDateString());
            info[6] = string.Format("Old ema1LowVol({0}) = {1:.####}", this.n1LowVolM, this.ema1LowVol0M);
            info[7] = string.Format("Old ema2HighVol({0}) = {1:.####}", this.n2HighVolM, this.ema2HighVol0M);
            info[8] = string.Format("Old volatility = {0:P1}", this.vol0M);
            return EMAEvaluator.vemaSignal(price1, vol1, this.n1LowVolM, ema1, this.n2HighVolM, ema2, this.volTM);
        }

        // Yesterday's signal value
        public override Signal oldAlert()
        {
            return EMAEvaluator.vemaSignal(this.price0M, this.vol0M, this.n1LowVolM, this.ema1LowVol0M, this.n2HighVolM, this.ema2HighVol0M, this.volTM);
        }

        public override void writeXml(XmlWriter writer)
        {
            base.writeXml(writer);
            writer.WriteElementString(N1_LOW_VOL_XML, n1LowVolM.ToString());
            writer.WriteElementString(N2_HIGH_VOL_XML, n2HighVolM.ToString());
            writer.WriteElementString(VOL_TREASHOLD, volTM.ToString());
        }

        public override string Description
        {
            get
            {
                return string.Format("{0,-8}: n1LowVol={1,-8} n2HighVol={2,-8} volT={3:P1}", base.XmlName, this.n1LowVolM, this.n2HighVolM, this.volTM);
            }
        }
    }
}
